/*
* Warpper a C style class to c++ class.
*
* @author: dzlua
* @contact: 505544956@qq.com
* @date: August 17, 2020
* @example: https://gitee.com/dzlua/test/blob/master/WrapperC/main.cc
*/

#ifndef __SDL_WRAPPER_HPP__
#define __SDL_WRAPPER_HPP__

namespace sdl {

template <typename T, typename C>
class Wrapper {
public:
	Wrapper(C* cptr = nullptr) noexcept { reset(cptr); }
	Wrapper(const Wrapper<T,C>& r) noexcept { reset(r.get()); }
	Wrapper<T,C>& operator=(const Wrapper<T,C>& r) noexcept { reset(r.get()); return *this; }
	Wrapper<T,C>& operator=(C* cptr) noexcept { reset(cptr); return *this; }
public:
	inline T* operator->() noexcept { return &obj_; }
	inline operator C* () const noexcept { return get(); }
	inline explicit operator bool() const noexcept { return get() != nullptr; }
public:
	inline C* get() const noexcept { return obj_.get(); }
	inline C*& set() noexcept { return obj_._set(); }
	inline void reset(C* cptr = nullptr) noexcept { obj_.reset(cptr); }
	inline void swap(Wrapper<T,C>& r) noexcept { obj_.swap(r.obj_); }
protected:
	T obj_;
};

template <typename T, typename C>
inline bool operator==(const Wrapper<T,C>& l, const Wrapper<T,C>& r) noexcept { return l.get() == r.get(); }
template <typename T, typename C>
inline bool operator==(const Wrapper<T,C>& l, std::nullptr_t) noexcept { return l.get() == nullptr; }
template <typename T, typename C>
inline bool operator==(std::nullptr_t, const Wrapper<T,C>& r) noexcept { return nullptr == r.get(); }
template <typename T, typename C>
inline bool operator!=(const Wrapper<T,C>& l, const Wrapper<T,C>& r) noexcept { return l.get() != r.get(); }
template <typename T, typename C>
inline bool operator!=(const Wrapper<T,C>& l, std::nullptr_t) noexcept { return l.get() != nullptr; }
template <typename T, typename C>
inline bool operator!=(std::nullptr_t, const Wrapper<T,C>& r) noexcept { return nullptr != r.get(); }

template <typename T, typename C>
class ClassWrapped {
	friend class Wrapper<T,C>;
protected:
	ClassWrapped(C *c = 0) : cptr_(c) {}
	virtual ~ClassWrapped() { reset(nullptr); }
	inline C* get() const noexcept { return cptr_; }
	inline C*& _set() noexcept { return cptr_; }
	inline void reset(C* cptr = nullptr) noexcept { cptr_ = cptr; }
	inline void swap(ClassWrapped<T,C>& r) noexcept { std::swap(cptr_, r.cptr_); }
protected:
	C* cptr_;
};

} // end namespace sdl

#endif // __SDL_WRAPPER_HPP__